//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "CathFASTAProfile.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <stdexcept>
#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 500000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathFASTAProfile::CathFASTAProfile() {

  this->domain                = new String ();
  this->format                = new String ();
  this->cathCode              = new String ();

  this->segments              = new TListE <SegmentCDDF> ();   
    
  this->sequence              = new String ();
  this->secondaryStructureP   = new String ();
  this->secondaryStructureC   = new String ();
  this->residuesClassChemical = new String ();
  this->residuesClassPhysical = new String ();
  this->residuesMT            = new String ();
    
  this->toString              = new String ();
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathFASTAProfile::CathFASTAProfile(const CathFASTAProfile& cathFASTAProfile) {

  this->domain                = new String (cathFASTAProfile.domain);
  this->format                = new String (cathFASTAProfile.format);
  this->cathCode              = new String (cathFASTAProfile.cathCode);

  this->segments              = new TListE <SegmentCDDF> (cathFASTAProfile.segments);   
    
  this->sequence              = new String (cathFASTAProfile.sequence);
  this->secondaryStructureP   = new String (cathFASTAProfile.secondaryStructureP);
  this->secondaryStructureC   = new String (cathFASTAProfile.secondaryStructureC);
  this->residuesClassChemical = new String (cathFASTAProfile.residuesClassChemical);
  this->residuesClassPhysical = new String (cathFASTAProfile.residuesClassPhysical);
  this->residuesMT            = new String (cathFASTAProfile.residuesMT);
    
  this->toString              = new String (cathFASTAProfile.toString);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathFASTAProfile::CathFASTAProfile(const CathFASTAProfile* cathFASTAProfile) {

  this->domain                = new String (cathFASTAProfile->domain);
  this->format                = new String (cathFASTAProfile->format);
  this->cathCode              = new String (cathFASTAProfile->cathCode);

  this->segments              = new TListE <SegmentCDDF> (cathFASTAProfile->segments);   
    
  this->sequence              = new String (cathFASTAProfile->sequence);
  this->secondaryStructureP   = new String (cathFASTAProfile->secondaryStructureP);
  this->secondaryStructureC   = new String (cathFASTAProfile->secondaryStructureC);
  this->residuesClassChemical = new String (cathFASTAProfile->residuesClassChemical);
  this->residuesClassPhysical = new String (cathFASTAProfile->residuesClassPhysical);
  this->residuesMT            = new String (cathFASTAProfile->residuesMT);
    
  this->toString              = new String (cathFASTAProfile->toString);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathFASTAProfile::~CathFASTAProfile() {

  if (this->domain)                 delete this->domain;
  if (this->format)                 delete this->format;
  if (this->cathCode)               delete this->cathCode;
  if (this->segments)               delete this->segments;   
  if (this->sequence)               delete this->sequence;   
  if (this->secondaryStructureP)    delete this->secondaryStructureP;   
  if (this->secondaryStructureC)    delete this->secondaryStructureC;   
  if (this->residuesClassChemical)  delete this->residuesClassChemical;   
  if (this->residuesClassPhysical)  delete this->residuesClassPhysical;   
  if (this->residuesMT)             delete this->residuesMT;   
    
  if (this->toString)               delete this->toString;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::Domain (String* domain) {
  
  if (domain) this->domain->In(domain);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::Format (String* format) {
  
  if (format) this->format->In(format);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::CathCode (String* cathCode) {
  
  if (cathCode) this->cathCode->In(cathCode);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::Segments (TListE <SegmentCDDF>* segments) {
  
  if (segments) *(this->segments) = *(segments);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::Sequence (String* sequence) {
  
  if (sequence) this->sequence->In(sequence);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::SecondaryStructureP (String* secondaryStructureP) {
  
  if (secondaryStructureP) this->secondaryStructureP->In(secondaryStructureP);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::SecondaryStructureC (String* secondaryStructureC) {
  
  if (secondaryStructureC) this->secondaryStructureC->In(secondaryStructureC);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::ResiduesClassChemical (String* residuesClassChemical) {
  
  if (residuesClassChemical) this->residuesClassChemical->In(residuesClassChemical);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::ResiduesClassPhysical (String* residuesClassPhysical) {
  
  if (residuesClassPhysical) this->residuesClassPhysical->In(residuesClassPhysical);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::ResiduesMT (String* residuesMT) {
  
  if (residuesMT) this->residuesMT->In(residuesMT);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::Domain (void) {
  
  return this->domain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::Format (void) {
  
  return this->format;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::CathCode (void) {
  
  return this->cathCode;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <SegmentCDDF>* CathFASTAProfile::Segments (void) {
  
  return this->segments;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::Sequence (void) {
  
  return this->sequence;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::SecondaryStructureP (void) {
  
  return this->secondaryStructureP;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::SecondaryStructureC (void) {
  
  return this->secondaryStructureC;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::ResiduesClassChemical (void) {
  
  return this->residuesClassChemical;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::ResiduesClassPhysical (void) {
  
  return this->residuesClassPhysical;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::ResiduesMT (void) {
  
  return this->residuesMT;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool CathFASTAProfile::ReadFromString (String* data) {

  if (!data || !data->Length()) return false;
  
  this->CleanData();
  
  char   tmpData [data->Length() + 1];
  char*  lines = NULL;
  
  String header;
  
  strcpy(tmpData, data->Out());
  tmpData[data->Length()] = '\0';

  lines = strtok(tmpData, "\n");
  
  while (lines) {

    if      (lines[0] == '>') { header.In(lines + 1);                       header.Trim();                        }
    else if (lines[0] == '<') { this->sequence->In(lines + 1);              this->sequence->RTrim();              }
    else if (lines[0] == '+') { this->secondaryStructureP->In(lines + 1);   this->secondaryStructureP->RTrim();   }
    else if (lines[0] == '-') { this->secondaryStructureC->In(lines + 1);   this->secondaryStructureC->RTrim();   }
    else if (lines[0] == ':') { this->residuesClassChemical->In(lines + 1); this->residuesClassChemical->RTrim(); }
    else if (lines[0] == ';') { this->residuesClassPhysical->In(lines + 1); this->residuesClassPhysical->RTrim(); }
    else if (lines[0] == '!') { this->residuesMT->In(lines + 1);            this->residuesMT->RTrim();            }
    
    lines = strtok(NULL, "\n");

  }
  
  if (header.Length()) {
    
    strcpy(tmpData, header.Out());
    
    lines = strtok(tmpData, " ");
    if (lines) { this->domain->In(lines); this->domain->RTrim(); }
    
    lines = strtok(NULL, " ()");
    if (lines) { this->format->In(lines); this->format->RTrim(); }
    
    bool readSegment = false;
    
    lines = strtok(NULL, " ");
    if (lines) { 
      
      if (lines[0] == '-') { 
        
        lines = strtok(NULL, " ");
        
        this->cathCode->In(lines); 
        this->cathCode->RTrim(); 
        
      }
      else if (lines[0] == '=') {
        
        readSegment = true;
        
        lines = strtok(NULL, " [;]");
        
        while (lines) {
          
          SegmentCDDF* newSegment = new SegmentCDDF ();
          newSegment->StoreData(lines);
          
          this->segments->Add(newSegment);
          
          lines = strtok(NULL, " [;]");
          
        }
        
      }
      
    }
    
    if (!readSegment) {
      
      lines = strtok(NULL, " ");
      
      if (lines && lines[0] == '=') {

        lines = strtok(NULL, " [;]");

        while (lines) {

          SegmentCDDF* newSegment = new SegmentCDDF ();
          newSegment->StoreData(lines);

          this->segments->Add(newSegment);

          lines = strtok(NULL, " [;]");

        }

      }
      
    }
    
    this->segments->SetInitial();
    while (this->segments->SetNext())
      this->segments->GetCurrent()->ReadPair();
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool  CathFASTAProfile::ReadFromString (char* data) {
  
  if (!data) return false;
  
  String dataChar;
  dataChar.In(data);
  
  return this->ReadFromString(&dataChar);    
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::ToStringSegment (void) {
  
  this->toString->In("");
  
  char buffer [LENGTHTEXT + 1];
  bool first = true;
  
  buffer[0] = '\0';
  
  this->segments->SetInitial();
  
  while (this->segments->SetNext()) {
    
    SegmentCDDF* currentSegment = this->segments->GetCurrent();
    
    sprintf (buffer, (first)?"%s%d-%d\0":"%s;%d-%d\0",  buffer, currentSegment->RangeStart(), currentSegment->RangeEnd());
    
    first = false;
    
  }
  
  this->toString->In(buffer);
  
  return this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::ToString (void) {
  
  char    buffer [LENGTHTEXT + 1];
  
  sprintf(buffer, ">%s (%s) - %s = [%s]\n<%s\n+%s\n-%s\n:%s\n;%s\n!%s\0", this->domain->Out(), 
                                                                          this->format->Out(), 
                                                                          this->cathCode->Out(), 
                                                                          this->ToStringSegment()->Out(),
                                                                          this->sequence->Out(),
                                                                          this->secondaryStructureP->Out(),
                                                                          this->secondaryStructureC->Out(),
                                                                          this->residuesClassChemical->Out(),
                                                                          this->residuesClassPhysical->Out(),
                                                                          this->residuesMT->Out());
  
  this->toString->In(buffer);
  
  return this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathFASTAProfile::ToStringHeader (void) {
  
  char    buffer [LENGTHTEXT + 1];
  
  sprintf(buffer, ">%s (%s) - %s = [%s]\0", this->domain->Out(), 
                                            this->format->Out(), 
                                            this->cathCode->Out(), 
                                            this->ToStringSegment()->Out());
  
  this->toString->In(buffer);
  
  return this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathFASTAProfile::CleanData (void) {
  
  this->domain->In("");
  this->format->In("");
  this->cathCode->In("");

  this->segments->Clear();
  
  this->sequence->In("");
  this->secondaryStructureP->In("");
  this->secondaryStructureC->In("");
  this->residuesClassChemical->In("");
  this->residuesClassPhysical->In("");
  this->residuesMT->In("");

  this->toString->In("");
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathFASTAProfile CathFASTAProfile::operator= (const CathFASTAProfile& cathFASTAProfile) {
  
  this->domain->In(cathFASTAProfile.domain);
  this->format->In(cathFASTAProfile.format);
  this->cathCode->In(cathFASTAProfile.cathCode);

  *(this->segments) = *(cathFASTAProfile.segments);   

  this->sequence->In(cathFASTAProfile.sequence);
  this->secondaryStructureP->In(cathFASTAProfile.secondaryStructureP);
  this->secondaryStructureC->In(cathFASTAProfile.secondaryStructureC);
  this->residuesClassChemical->In(cathFASTAProfile.residuesClassChemical);
  this->residuesClassPhysical->In(cathFASTAProfile.residuesClassPhysical);
  this->residuesMT->In(cathFASTAProfile.residuesMT);
  
  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
